#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX_LINE_LENGTH 512

#define DFU_CMD_CONNECT         0xa0
#define DFU_CMD_READ            0xa1
#define DFU_CMD_PROGRAM         0xa2
#define DFU_CMD_ERASE           0xa3
#define DFU_CMD_REBOOT          0xa4

#define STATUS_OK               0x00
#define STATUS_ERRORCMD         0x01
#define STATUS_OUTOFRANGE       0x02
#define STATUS_PROGRAMERR       0x03
#define STATUS_ERRORWRAP        0xff
#define DFU_CMD_PRINTF          0x04


#define UART_TX_BUFFER_SIZE 256

typedef unsigned char BYTE;
typedef unsigned long DWORD;

BYTE UartTxBuffer[UART_TX_BUFFER_SIZE];


BYTE UartTxBuffer[UART_TX_BUFFER_SIZE];
BYTE UartTxIndex;
BYTE UartTxSum;
unsigned char line[MAX_LINE_LENGTH];


int uart_receive(int uart_fd, unsigned char *buffer, int length) {
    usleep(10000);
    int total_read = 0;
    while (total_read < length) {
        int bytes_read = read(uart_fd, buffer + total_read, length - total_read);
        if (bytes_read > 0) {
            total_read += bytes_read;
        } else if (bytes_read == 0) {
            break; // No more data
        } else {
            perror("UART Read");
            return -1;
        }
    }
    return total_read;
}
// 配置串口参数
int configure_serial_port(int uart_fd, int baud_rate) {
    struct termios options;
    tcgetattr(uart_fd, &options);

    // 设置波特率
    cfsetispeed(&options, baud_rate);
    cfsetospeed(&options, baud_rate);

    // 设置字符大小，停止位和奇偶校验
    options.c_cflag &= ~PARENB;    // 无奇偶校验
    options.c_cflag &= ~CSTOPB;    // 1个停止位
    options.c_cflag &= ~CSIZE;     // 清除当前的字符大小掩码
    options.c_cflag |= CS8;        // 8位字符

    // 配置读取操作
    options.c_cflag |= CREAD | CLOCAL;  // 打开接收器并设置本地模式
    options.c_iflag &= ~(IXON | IXOFF | IXANY); // 禁用软件流控制
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 设置为原始模式
    options.c_oflag &= ~OPOST; // 设置为原始输出

    // 应用设置
    tcflush(uart_fd, TCIFLUSH);
    tcsetattr(uart_fd, TCSANOW, &options);
    return 0;
}


// 打开串口
int open_serial_port(const char* port_name, int baud_rate) {
    int uart_fd = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY);
    if (uart_fd == -1) {
        perror("Unable to open UART");
        return -1;
    }

    // 配置串口
    configure_serial_port(uart_fd, baud_rate);
    return uart_fd;
}



// 发送数据到串口
void send_data(int uart_fd, const char* data) {
    printf("data len: %d",strlen(data));
    int len = write(uart_fd, data, strlen(data));
    if (len < 0) {
        perror("UART TX error");
    }
}



void send_data_to_uart(int uart_fd, const char *sendbuf, size_t buf_size) {
    size_t bytes_sent = 0;
    while (bytes_sent < buf_size) {
        ssize_t result = write(uart_fd, sendbuf + bytes_sent, buf_size - bytes_sent);
        if (result < 0) {
            perror("Error writing to UART");
            break;
        }
        
        bytes_sent += result;
    }
}





// 封装发送数据包函数
int uart_packet(BYTE *data, BYTE length)
{
    BYTE i;

    // 初始化发送累加和
    UartTxSum = 0;
    UartTxIndex = 0;

    // 发送起始字符
    UartTxBuffer[UartTxIndex++] = '#';
    UartTxSum += '#';

    // 发送长度字节
    UartTxBuffer[UartTxIndex++] = length;
    UartTxSum += length;

    // 发送数据内容
    for (i = 0; i < length; i++)
    {
        UartTxBuffer[UartTxIndex++] = data[i];
        UartTxSum += data[i];   
    }

    // 发送结束字符
    UartTxBuffer[UartTxIndex++] = '$';
    // UartTxSum += '$';
    // // 发送累加和校验    
    UartTxBuffer[UartTxIndex++] = -UartTxSum;
    return (int)UartTxIndex;
}

void uart_send_packet(int uart_fd, const char *sendbuf, size_t buf_size)
{

}

//解析数据
int parse_uart_buffer(BYTE *buffer, int buffer_size, BYTE *status, BYTE *size, BYTE *data) {
    BYTE sum = 0;
    BYTE received_sum;
    int i;

    // 检查缓冲区大小是否足够
    if (buffer_size < 5) { // 至少需要5个字节：包头、状态、大小、包尾、校验和
        return -1; // 错误处理：缓冲区大小不足
    }

    // 检查包头
    if (buffer[0] != 0xF1) {
        printf("size fail\r\n");
        return -2; // 错误处理：包头不正确
    }

    // 读取状态和大小
    *status = buffer[1];
     sum   +=0xF1;
    sum += *status;

    *size = buffer[2];
    sum += *size;

    // 检查缓冲区大小是否足够容纳数据
    if (buffer_size < 4 + *size) { // 头2字节 + 数据长度 + 尾2字节
       printf("size fail\r\n");
        return -3; // 错误处理：缓冲区大小不足
    }

    // 读取数据
    for (i = 0; i < *size; i++) {
        data[i] = buffer[3 + i];
        sum += data[i];
    }

    // 检查包尾
  
    if (buffer[3 + *size] != '$') {
         printf(" $ error\r\n");
        return -4; // 错误处理：包尾不正确
    }

    // 读取校验和
    sum+=buffer[3 + *size];
    received_sum = buffer[4 + *size];
    if (received_sum != (BYTE)(-sum)) {
        printf("received_sum error:%x\r\n",-sum);
        return -5; // 错误处理：校验和不正确
    }   

    return 0; // 成功解析
}


int read_response(int uart_fd,BYTE* data)
{
    //接收响应
    BYTE status;
    BYTE size;

    int length=16;
    BYTE* buffer= (BYTE* )malloc(length*sizeof(BYTE));
    if(buffer==NULL)
    {
        return -1;
    }

    usleep(10000);
    int bytes_received = uart_receive(uart_fd, buffer, length);

    for(int i=0;i<bytes_received;i++)
    {
        printf("%x ",buffer[i]);
    }

    printf("\r\n");

    if(parse_uart_buffer(buffer,length,&status,&size,data)!=0)
    {
        //printf("response error\r\n");
        return -2;
    }

    if(STATUS_ERRORCMD==status)
    {
        //printf("STATUS_ERRORCMD\r\n");
        return -3;
    }

    free(buffer);
    return 0;
}


int dfu_connect(int uart_fd)
{
    //发送数据包

    usleep(20000);
    BYTE packet[1];
    packet[0] = DFU_CMD_CONNECT;
    int len=uart_packet(packet, 1);//封装数据包
    send_data_to_uart(uart_fd,UartTxBuffer,len);

    BYTE* data=(BYTE*)malloc(2*sizeof(BYTE));
    int code=read_response(uart_fd,data);
    if(code<0)
    {
        
        return -1;//连接失败
    }
    return 0;
}


// 擦除命令
// 擦除命令
// 设置 UART 为阻塞模式
void set_blocking(int fd) {
    int flags = fcntl(fd, F_GETFL, 0);
    fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
}
void dfu_erase(int uart_fd)
{
    printf("erasing..........\r\n");
    BYTE packet[1];
    packet[0] = DFU_CMD_ERASE;
    int len=uart_packet(packet, 1);//封装数据包
    send_data_to_uart(uart_fd,UartTxBuffer,len);
    usleep(10000000);
    int code=read_response(uart_fd,NULL);
    if(code<0)
    {
        return -1;//连接失败
    }
}

//
void dfu_read(int uart_fd,DWORD addr,  BYTE size)
{
    BYTE packet[6];
    packet[0] = DFU_CMD_READ;

    packet[1] = (addr >> 24) & 0xFF;   
    packet[2] = (addr >> 16) & 0xFF;  
    packet[3] = (addr >> 8) & 0xFF;  
    packet[4] = addr & 0xFF; 
    // *(DWORD *)&packet[1] = addr;


    packet[5] = size;
  //  memcpy(&packet[6], data, size);
    int len=uart_packet(packet, 6 );//封装数据包
    send_data_to_uart(uart_fd,UartTxBuffer,len);
    for(int i=0;i<len;i++)
    {
        printf("%x\r\n",UartTxBuffer[i]);
    }
}

//写入命令
void dfu_program(int uart_fd,DWORD addr,BYTE *data,  BYTE size)
{
    printf("%06lX: ", addr);
    for(int i=0;i<size;i++)
    {
        printf("%x ",data[i]);
    }
     printf("\r\n");

    BYTE packet[6 + size];
    packet[0] = DFU_CMD_PROGRAM;

    packet[1] = (addr >> 24) & 0xFF;   
    packet[2] = (addr >> 16) & 0xFF;  
    packet[3] = (addr >> 8) & 0xFF;  
    packet[4] = addr & 0xFF; 
    packet[5] = size;

    memcpy(&packet[6], data, size);
    int len=uart_packet(packet, 6 + size);//封装数据包
    send_data_to_uart(uart_fd,UartTxBuffer,len);
}

// 重启命令
void dfu_reboot(int uart_fd)
{
    BYTE packet[1];
    packet[0] = DFU_CMD_REBOOT;
    int len=uart_packet(packet, 1);//封装数据包
    send_data_to_uart(uart_fd,UartTxBuffer,len);
    // for(int i=0;i<len;i++)
    // {
    //     printf("%x\r\n",UartTxBuffer[i]);
    // }
}


// 从文件中读取每一行并发送
void read_and_send_file(int uart_fd,DWORD addr,const char *filename)
{
    BYTE packet[6];
    packet[0] = DFU_CMD_PROGRAM;

    packet[1] = (addr >> 24) & 0xFF;   
    packet[2] = (addr >> 16) & 0xFF;  
    packet[3] = (addr >> 8) & 0xFF;  
    packet[4] = addr & 0xFF; 

    for(int i=1;i<5;i++)
    {
        printf("%x ",packet[i]);
    }

   printf("\r\n");

   FILE *file = fopen(filename, "r");
    if (file == NULL)
    {
        perror("Error opening file");
        return;
    }

    while (fgets(line, sizeof(line), file))
    {
        // 去除换行符
        line[strcspn(line, "\n")] = 0;

        // 计算每行的字节数
        size_t line_length = strlen(line) / 3 ; // 每个字节占2个字符，加1个空格
        BYTE *data = (BYTE *)malloc(line_length * sizeof(BYTE));
        if (data == NULL)
        {
            perror("Memory allocation error");
            fclose(file);
            return;
        }

        // 将每行的十六进制字符串转换为字节数组
        for (size_t i = 0, j = 0; i < strlen(line); i += 3, j++)
        {
            sscanf(&line[i], "%2hhx", &data[j]);
        }

        // 发送数据包
        addr+=line_length;
        dfu_program(uart_fd,addr,data,line_length);
        usleep(20);
        free(data);
    }

    fclose(file);
}





// 将两个十六进制字符转换为一个字节
unsigned char hexToByte(const char *hex) {
    unsigned char byte = 0;
    for (int i = 0; i < 2; ++i) {
        byte <<= 4;
        if (hex[i] >= '0' && hex[i] <= '9') {
            byte |= (hex[i] - '0');
        } else if (hex[i] >= 'A' && hex[i] <= 'F') {
            byte |= (hex[i] - 'A' + 10);
        } else if (hex[i] >= 'a' && hex[i] <= 'f') {
            byte |= (hex[i] - 'a' + 10);
        }
    }
    return byte;
}

// 解析一行Intel HEX文件
int zeroAddressCount=0;
unsigned long currentHighAddress=0;
void parseHexLine(int uart_fd,const char *line) {
    if (line[0] != ':') {
        fprintf(stderr, "Invalid line: %s\n", line);
        return;
    }

    int byteCount = hexToByte(&line[1]);
    unsigned long address = (hexToByte(&line[3]) << 8) | hexToByte(&line[5]);
    int recordType = hexToByte(&line[7]);

    BYTE *data = (BYTE *)malloc(byteCount);
    if (data == NULL)
    {
        perror("Memory allocation error");
        return;
    }

    if (recordType == 0x00) {  // Data record   
        unsigned long adjustedAddress = (currentHighAddress << 16) | address;
        // 打印数据

        if(adjustedAddress==0xFF0000)
        {
            adjustedAddress=0xFF1000;
        }
        for (int i = 0; i < byteCount; ++i) {
            unsigned char tmp = hexToByte(&line[9 + i * 2]);
            data[i]=tmp;
        }

        dfu_program(uart_fd,adjustedAddress,data,byteCount);
        free(data);
    } 
    else if (recordType == 0x01) {  // End of File record
        free(data);
        return;
    } 
    else if (recordType == 0x04) {  // Extended Linear Address Record
        currentHighAddress = (hexToByte(&line[9]) << 8) | hexToByte(&line[11]);
        free(data);
    }
    else {
        printf("Unsupported record type: %02X\n", recordType);
    }
}





int main(int argc, char *argv[])
{
    const char* port_name = "/dev/ttyS2"; // 根据实际情况更改设备名
    //int baud_rate = B9600;
    int baud_rate = B115200;

    // 打开串口
    int uart_fd = open_serial_port(port_name, baud_rate);

    if (uart_fd == -1) {
        return -1;
    }

    int code=dfu_connect(uart_fd);
    int i=0;
    printf("connect........\r\n");
    while(code<0)
    {
        code=dfu_connect(uart_fd);
        i++;
        if(i>60)
        {
            printf("connect fail\r\n");
            return 0;
        }
    }
    printf("connect success........\r\n");


    dfu_erase(uart_fd);

    FILE *hexFile = fopen(argv[1], "r");
    if (hexFile == NULL) {
        perror("Failed to open input file");
        return 1;
    }


    while (fgets(line, sizeof(line), hexFile)) {
        parseHexLine(uart_fd,line);
        usleep(20);
    }

    usleep(1000);
    dfu_reboot(uart_fd);
   // dfu_program(uart_fd,0xFF0000,data,length);
   // dfu_connect(uart_fd);
  //  dfu_erase(uart_fd);
   // dfu_read(uart_fd,0xFF1000,100);
  // 发送数据包
    return 0;
}
